import java.util.Map;

public class bfuncs {

    //entry
    public boolean bfunc(final String funcName, final Map<String, Map<String, String>> vcMap) throws Exception {
        if("same".equals(funcName)){
            return funcSame(vcMap);
        } else if ("sz_loc_range".equals(funcName)) {
            return funcSZLocRange(vcMap);
        } else if ("sz_loc_close".equals(funcName)) {
            return funcSZLocClose(vcMap);
        } else if ("sz_spd_close".equals(funcName)) {
            return funcSZSpdClose(vcMap);
        } else if ("sz_loc_dist".equals(funcName)) {
            return funcSZLocDist(vcMap);
        } else {
            throw new Exception("Unknown function: " + funcName);
        }
    }

    // Compares two field values and a constant string i f any (should be identical)
    private boolean funcSame(Map<String, Map<String, String>> varEnv)  {
        Map<String, String> ctx1 = varEnv.get("v1");
        Map<String, String> ctx2 = varEnv.get("v2");

        return ctx1.get("subject").equals(ctx2.get("subject"));
    }


    // For taxi
    private boolean funcSZLocRange(Map<String, Map<String, String>> varEnv)  {
        Map<String, String> ctx1 = varEnv.get("v1");
        double lon = Double.parseDouble(ctx1.get("longitude"));
        double lat = Double.parseDouble(ctx1.get("latitude"));
        return !(lon < 2.0) && !(lon > 6.0) && !(lat < 0.0) && !(lat > 4.0);
    }

    // For taxi

    private boolean funcSZLocClose(Map<String, Map<String, String>> varEnv) {

        Map<String, String> ctx1 = varEnv.get("v1");
        Map<String, String> ctx2 = varEnv.get("v2");

        double lon1 = Double.parseDouble(ctx1.get("longitude"));
        double lat1 = Double.parseDouble(ctx1.get("latitude"));
        double lon2 = Double.parseDouble(ctx2.get("longitude"));
        double lat2 = Double.parseDouble(ctx2.get("latitude"));

        double distSq = (lon2 - lon1) * (lon2 - lon1) + (lat2 - lat1) * (lat2 - lat1);
        // The distance should be no more than 0.001 as 'close'
        return !(distSq > 0.001 * 0.001);
    }

    // For taxi

    private boolean funcSZSpdClose(Map<String, Map<String, String>> varEnv)  {

        Map<String, String> ctx1 = varEnv.get("v1");
        Map<String, String> ctx2 = varEnv.get("v2");

        int speed1 = Integer.parseInt(ctx1.get("speed"));
        int speed2 = Integer.parseInt(ctx2.get("speed"));
        // The difference should be no more than 50 (as 'close')
        return Math.abs(speed2 - speed1) <= 50;
    }

    // For taxi

    private boolean funcSZLocDist(Map<String, Map<String, String>> varEnv) {

        Map<String, String> ctx1 = varEnv.get("v1");
        Map<String, String> ctx2 = varEnv.get("v2");

        double lon1 = Double.parseDouble(ctx1.get("longitude"));
        double lat1 = Double.parseDouble(ctx1.get("latitude"));
        double lon2 = Double.parseDouble(ctx2.get("longitude"));
        double lat2 = Double.parseDouble(ctx2.get("latitude"));

        double distSq = (lon2 - lon1) * (lon2 - lon1) + (lat2 - lat1) * (lat2 - lat1);

        // The distance should be no more than 0.025 (assuming that the speed is no more than 200 km/h)
        return !(distSq > 0.025 * 0.025);
    }
}